package com.easy.api.registry;

import com.easy.api.annotation.ApiProxy;
import com.easy.api.factory.api.ApiProxyFactory;
import com.easy.api.factory.file.FileConversionFactory;
import com.easy.api.utils.ApplicationContextUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;
import org.springframework.util.SystemPropertyUtils;

import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * @Author liuyuan
 * @Date 2020-01-16 11:23
 * @Version 1.0
 */
@Component
public class ApiRegistryBean implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware, ResourceLoaderAware {


    private static ApplicationContext applicationContext;

    private final String EASY_API_CONFIGURATION ="easyApiConfiguration";

    /**
     * Spring容器注入
     */
    private ResourceLoader resourceLoader;

    private ResourcePatternResolver resolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
    private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
   //private static final String FULLTEXT_SACN_PACKAGE_PATH = "com.channel";

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        Set<Class<?>> classes = null;
        try {
            if(applicationContext == null){
                throw new RuntimeException("applicaitonContext属性为null,请检查是否注入了applicaitonContext!");
            }
            ApplicationContextUtils.applicationContext = applicationContext;
            Map<String, Object> beansWithAnnotationMap = applicationContext.getBeansWithAnnotation(ComponentScan.class);
            Object easyApiConfiguration = beansWithAnnotationMap.get(EASY_API_CONFIGURATION);
            Class<? extends Object> clazz = easyApiConfiguration.getClass();
            ComponentScan annotation = AnnotationUtils.findAnnotation(clazz, ComponentScan.class);
            if(annotation != null){
                String[] sacn_package_path = annotation.basePackages();
                for (String package_path : sacn_package_path) {
                    if(null == package_path){
                        continue;
                    }
                    Set<Class<?>> interfaceClass = doScan(package_path);
                    if(interfaceClass == null){
                        continue;
                    }
                    if(classes == null){
                        classes = interfaceClass;
                    }else {
                        classes.addAll(interfaceClass);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        if(classes != null){
            Iterator<Class<?>> it = classes.iterator();
            while (it.hasNext()) {
                Class<?> next = it.next();
                // 需要被代理的接口
                BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(next);
                GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition();
                definition.getPropertyValues().add("interfaceClass", definition.getBeanClassName());
                ApiProxy annotation = next.getAnnotation(ApiProxy.class);
                if(annotation != null){
                    definition.setBeanClass(ApiProxyFactory.class);
                }else {
                    definition.setBeanClass(FileConversionFactory.class);
                }

                //definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
                // 注册bean名,一般为类名首字母小写
                String className = getClassName(next.getName());
                System.out.println("className:"+className);
                beanDefinitionRegistry.registerBeanDefinition(className, definition);
            }
        }


    }



    private String getClassName(String classPath){
        String replace = classPath.replace(".", "/");
        String[] splits = replace.split("/");
        String name = splits[splits.length - 1];
        return toLowerCaseFirstOne(name);
    }


    //首字母转小写
    public static String toLowerCaseFirstOne(String s){
        if(Character.isLowerCase(s.charAt(0)))
            return s;
        else
            return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
    }





    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {


    }


    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        if (this.resourceLoader == null) {
            this.resourceLoader = resourceLoader;
        }

    }

    /**
     * 利用spring提供的扫描包下面的类信息,再通过classfrom反射获得类信息
     *
     * @param scanPath
     * @return
     * @throws IOException
     */
    public Set<Class<?>> doScan(String scanPath) throws IOException {
        Set<Class<?>> classes = new HashSet<Class<?>>();
        String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
                .concat(ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(scanPath))
                        .concat("/**/*.class"));
        Resource[] resources = resolver.getResources(packageSearchPath);
        MetadataReader metadataReader = null;
        for (Resource resource : resources) {
            if (resource.isReadable()) {
                metadataReader = metadataReaderFactory.getMetadataReader(resource);
                try {
                    // 当类型是抽象类或接口在添加到集合
                    if (!metadataReader.getClassMetadata().isConcrete()) {
                        classes.add(Class.forName(metadataReader.getClassMetadata().getClassName()));
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            }
        }
        return classes;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

}
